module Orator

  # This handles events and calls the callbacks for them.
  class EventHandler

    # This is the router the event handler will use to map the events to the
    # orators.
    #
    # @return [Router]
    attr_accessor :router

    # Initialize the event handler.
    #
    # @param router [Router] the router that the event handler will use.
    # @yields [] in the current instance.  Mainly for setting up the events.
    # @return [void]
    def initialize(router = nil, &block)
      @router  = router
      @_number = 0
      instance_exec &block if block_given?
    end

    # This triggers an event with the given context and arguments.  This is the
    # point where it DOES load the orator classes.
    #
    # @param event [String] the event to run.
    # @param context [Object] the context to run it in.
    # @return [void]
    def trigger(event, context, *args)
      data = router.find(event)

      if !data && Orator.debug
        data = router.find("socket.missing")
      end

      raise NoEventError, "No event named `#{event}` exists." unless data

      if data[:to].is_a?(Proc)
        return context.instance_exec *args, &data[:to]
      end

      if data[:to].is_a?(String)
        klass = data[:to].constantize
      elsif data[:to].is_a?(Class)
        klass = data[:to]
      end

      instance = klass.new(context, data)

      instance.run_callbacks(:before, args)
      instance.__send__(data[:method], *args) unless instance.prevent_event?
      instance.run_callbacks(:after, args)

    end

  end

  class NoEventError < StandardError; end

end
